import type {
  AxiosError,
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios'
import axios from 'axios'
import { message } from 'antd'
import { toLogin } from './toLogin'

const baseUrlStr = import.meta.env.VITE_APP_BASE_API

// 不同的环境，使用不同的baseUrl
const baseUrlAry = [
  import.meta.env.VITE_APP_BASE_API,
  import.meta.env.VITE_APP_FIRST_API,
  import.meta.env.VITE_APP_SECOND_API,
]

// 创建 axios 实例
const baseURL =
  import.meta.env.MODE === 'development'
    ? baseUrlStr
    : `${window.location.origin}`

// 正常请求的axios实例
const service: AxiosInstance = axios.create({
  baseURL,
  timeout: 50000,
})

// 刷新token专用的axios实例
const serviceRefreshToken = axios.create({
  baseURL,
  timeout: 50000,
})

interface MyAxiosRequestConfig extends InternalAxiosRequestConfig {
  port?: string
}

/* 请求拦截器 */
service.interceptors.request.use(
  (config: MyAxiosRequestConfig) => {
    const accessToken = localStorage.getItem('accessToken')
    // 切换不同的baseUrl
    if (config.url?.includes('demo')) {
      config.baseURL = baseUrlAry[1]
    }
    // 从本地存储中获取 token
    if (accessToken) {
      config.headers.token = accessToken
    }
    return config
  },
  (error: AxiosError) => {
    message.error(error.message)
    return Promise.reject(error)
  },
)
// 这里是正常获取数据用的响应拦截器，正常数据请求都是1状态码，当拦截到-110 代表token无效，拦截到-103 代表token鉴权失败
// 加上防止token过期后正好短时间内多个请求重复刷新token，刷新token成功再请求
let isRefreshing = false
let refreshFnArr: any[] = []
/* 响应拦截器 */
service.interceptors.response.use(
  async (response: AxiosResponse) => {
    let res = response.data
    if (res.code === 1) {
      return res
    } else if (res.code == -110 || res.code == -103) {
      toRefToken(response)
      return res
    } else if (res.code === -1) {
      message.error(res.msg)
      return res
    } else {
      return res
    }
  },
  (error: AxiosError) => {
    const errData: any = error.response?.data
    if (
      error.response?.status === 401 &&
      (errData.code === -110 || errData.code === -103)
    ) {
      toRefToken(error)
      console.log('🌺报了大错=》')
    }

    // if (errData.code === -103) {
    // message.error(errData.msg)
    // 清除token
    // localStorage.setItem('accessToken', '')
    // 使用 refacetoken 刷新accessToken
    // shuaxinToken()
    // return errData
    // }

    message.error(error.message)
    return Promise.reject(error)
  },
)

/* 导出封装的请求方法 */
const http = {
  get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
    return service.get(url, config)
  },

  post<T = any>(
    url: string,
    data?: object,
    config?: AxiosRequestConfig,
  ): Promise<T> {
    return service.post(url, data, config)
  },

  put<T = any>(
    url: string,
    data?: object,
    config?: AxiosRequestConfig,
  ): Promise<T> {
    return service.put(url, data, config)
  },

  delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
    return service.delete(url, config)
  },

  download(
    url: string,
    params?: object,
    config?: AxiosRequestConfig,
  ): Promise<BlobPart> {
    return service.post(url, params, { ...config, responseType: 'blob' })
  },
}

export default http

//获取新token的方法
const getNewToken = async () => {
  try {
    let res = await serviceRefreshToken.request({
      url: `/refreshToken`,
      method: 'get',
      headers: {
        token: sessionStorage.getItem('refreshToken'),
      },
    })

    console.log('🌺👉 res.datares.data==》', res.data)
    //  10: 鉴权失败； 20： token 无效； 30： 生成新 token 失败； 0： 成功
    if (res.data.code === 0) {
      localStorage.setItem('accessToken', res.data.token)
      console.log('🌺👉空间==》', res.data.code)
      return true
    } else {
      //跳转到首页
      message.error(res.data.msg)
      toLogin()
      message.error(res.data)
      return false
    }
  } catch (error) {
    console.log('🌺👉 刷新token失败了=》', error)
    message.error('刷新token失败了')
    return false
  }
}

// 这里是刷新token专用的axios对象，他的作用是给请求加上刷新token专用的refreshToken
serviceRefreshToken.interceptors.request.use(
  (config) => {
    let refreshToken: string | null = ''
    refreshToken = sessionStorage.getItem('refreshToken')
    if (refreshToken) {
      config.headers.token = refreshToken
    }
    return config
  },
  (error) => {
    Promise.reject(error)
  },
)
/*
  这里是刷新token的逻辑，
  1. 首先判断是否正在刷新token，如果是，就把请求加入到数组中，等待刷新token成功后再请求
  2. 如果不是，就请求刷新token，如果刷新token成功，就把数组中的请求全部执行一遍
  3. 如果刷新token失败，就跳转到登录页
*/
const toRefToken = async (res: any) => {
  if (!isRefreshing) {
    // 如果正好段时间内触发了多个请求
    isRefreshing = true
    console.log('🌺👉 blblbl 1111==》', isRefreshing)
    const bl = await getNewToken()
    console.log('🌺👉 blblbl 22222==》', bl, refreshFnArr)

    if (bl) {
      refreshFnArr.forEach((fn) => {
        fn()
      })
      refreshFnArr = []
      console.log('🌺👉 why=》', res.config)
      res = await service.request(res.config)
      isRefreshing = false
    }
  } else {
    return new Promise((resolve) => {
      refreshFnArr.push(() => {
        resolve(res.config)
      })
    })
  }
}
